home *** CD-ROM | disk | FTP | other *** search
/ Multimedia Jumpstart / Multimedia Microsoft Jumpstart Version 1.1a (Microsoft).BIN / develpmt / source / trans / trle.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-11  |  6.7 KB  |  301 lines

  1. /*--------------------------------------------------------------------------*\
  2. |   TRLE.C - Convert DIBs into transparent RLEs
  3. \*--------------------------------------------------------------------------*/
  4.  
  5. #include <windows.h>
  6. #include <windowsx.h>
  7. #include "dib.h"
  8.  
  9. #ifdef WIN32
  10.     #include <memory.h>
  11.     #define  _huge
  12.     #define  hmemcpy memcpy
  13. #endif
  14.  
  15. //
  16. // you can control what type of pointers this code uses by defining
  17. // PRLE to be _huge, _far, or what ever.
  18. //
  19.  
  20. //typedef BYTE *PRLE;
  21. //typedef BYTE FAR *PRLE;
  22. typedef BYTE _huge *PRLE;
  23.  
  24. #define RLE_ESCAPE  0
  25. #define RLE_EOL     0
  26. #define RLE_EOF     1
  27. #define RLE_JMP     2
  28. #define RLE_RUN     3
  29.  
  30. #define GEN_JMP(p,dx,dy) {   \
  31.     if (dx != 0 || dy != 0)  \
  32.     {                    \
  33.     *(p)++ = RLE_ESCAPE; \
  34.     *(p)++ = RLE_JMP;    \
  35.     *(p)++ = (BYTE)(dx); \
  36.     *(p)++ = (BYTE)(dy); \
  37.     }}
  38.  
  39. #define GEN_EOL(p) { \
  40.     *(p)++ = RLE_ESCAPE; \
  41.     *(p)++ = RLE_EOL; }
  42.  
  43. #define GEN_EOF(p) { \
  44.     *(p)++ = RLE_ESCAPE; \
  45.     *(p)++ = RLE_EOF; }
  46.  
  47. #define GEN_ABS(p,cnt) { \
  48.     *(p)++ = RLE_ESCAPE; \
  49.     *(p)++ = (BYTE)(cnt); }
  50.  
  51. #define GEN_RUN(p,cnt,b) { \
  52.     *(p)++ = (BYTE)(cnt); \
  53.     *(p)++ = (BYTE)(b); }
  54.  
  55. #define GEN_JUMP(p,dx,dy) { int i; \
  56.     for (i=0; i<(dx)/255; i++)     \
  57.         GEN_JMP(p,255,0);          \
  58.                                    \
  59.     for (i=0; i<(dy)/255; i++)     \
  60.         GEN_JMP(p,0,255);          \
  61.                                    \
  62.     GEN_JMP(p,(dx)%255,(dy)%255); }
  63.  
  64. static void   NEAR PASCAL DeltaFrame(LPBITMAPINFOHEADER, PRLE, PRLE, PRLE);
  65. static PRLE   NEAR PASCAL EncodeFragment(PRLE pSource,PRLE pDest,int length);
  66.  
  67. //
  68. // FindJump
  69. //
  70. // This routine returns the number of pixels in the 2 DIBs that can be
  71. // skipped over, because they are the same, or close enough within the
  72. // specified tolerance.  It only checks one scan line.
  73. //
  74.  
  75. static int _inline FindJumpLength(
  76.     PRLE pb,
  77.     int  len,
  78.     UINT uColor)
  79. {
  80.         int  i;
  81.  
  82.     for (i=0; i<len && pb[i]==(BYTE)uColor; i++)
  83.             ;
  84.  
  85.         return i;
  86. }
  87.  
  88. //
  89. // SkipAhead
  90. //
  91. // this routine returns the number of pixels that are not the same
  92. // in the two DIBs, there must be a run of at least gMinJumpSize pixels
  93. // in order to stop. (or end of line)
  94. //
  95.  
  96. static int _inline FindFragmentLength(
  97.     PRLE pb,
  98.     int  len,
  99.     UINT uColor)
  100. {
  101.         int  i;
  102.  
  103.     for (i=0; i<len && pb[i]!=(BYTE)uColor; i++)
  104.             ;
  105.  
  106.         return i;
  107. }
  108.  
  109. /*
  110. ** Run-length encode wLength 8-bit pixels starting at pSource, storing
  111. ** the resulting data at pDest.
  112. */
  113. static PRLE NEAR PASCAL EncodeFragment(PRLE pSource,PRLE pDest,int length)
  114. {
  115.     int i,j;
  116.     BYTE b;
  117.     PRLE p;
  118.  
  119.     while (length) {
  120.     int nMaxLength;
  121.  
  122.     b = *pSource;
  123.     p = pSource;
  124.     nMaxLength = min(length, 255);
  125.     for (i = 1; (i < nMaxLength) && (b == *(++p)); i++)
  126.         ;
  127.     if (length < RLE_RUN || i > 1) {
  128.         GEN_RUN(pDest,i,b);
  129.         pSource += i;
  130.         length -= i;
  131.     } else {
  132.         for (j = RLE_RUN; (j < nMaxLength); j++) {
  133.         b = *(pSource+j);
  134.         p = pSource+j;
  135.             /* stop if you run out of data or you find a run */
  136.         for (i=1; i+j < length && i < RLE_RUN && (b == *(++p)); i++)
  137.             ;
  138.         if (i >= RLE_RUN)
  139.             break;
  140.         }
  141.         GEN_ABS(pDest,j);
  142.         length -= j;
  143.         i = j;
  144.         while (j--) {
  145.         *pDest++ = *pSource++;
  146.         }
  147.         if (i & 1)        /* Re-align after odd absolute run */
  148.         *pDest++ = '\0';    // Set unused byte for DIFF checking.
  149.     }
  150.     }
  151.             
  152.     return pDest;
  153. }
  154.  
  155. //
  156. // RleDib
  157. //
  158. // given a DIB make a RLE out of it, treating a passed color as transparent
  159. // the output buffer must be big enougth to hold the RLE, or bad things
  160. // will happen.
  161. //
  162. long RleDib(
  163.     LPBITMAPINFOHEADER lpbi,    // bitmap info
  164.     LPVOID             pDib,    // DIB to compress
  165.     UINT           uColor,    // trasnparent color (-1 for none)
  166.     LPVOID             pRle)    // RLE bits output
  167. {
  168.     PRLE    pbDib   = (PRLE)pDib;
  169.     PRLE    pbRle   = (PRLE)pRle;
  170.     PRLE    pbDibT  = pbDib;
  171.     PRLE    pbRleT  = pbRle;
  172.  
  173.     int     x,y;
  174.     int     dx,dy;
  175.     int     jx,jy;              // delta jump values
  176.  
  177.     WORD    wNextScan;
  178.     WORD    wWidthBytes;
  179.  
  180.     if (lpbi->biBitCount != 8 || lpbi->biCompression != 0)
  181.         return 0;
  182.  
  183.     dx = (int)lpbi->biWidth;
  184.     dy = (int)lpbi->biHeight;
  185.  
  186.     //
  187.     //  Calc next scan values, value to add to pointer when it is at the
  188.     //  end of the scan to get to the begining of the next.
  189.     //
  190.     wWidthBytes = (dx+3)&~3;
  191.     wNextScan   = wWidthBytes - dx;
  192.     
  193.     if (uColor == (UINT)-1)  // just RLE it
  194.     {
  195.         for (y=0; y<dy; y++)
  196.         {
  197.             if (y > 0)
  198.                 GEN_EOL(pbRle);
  199.  
  200.             pbRle = EncodeFragment(pbDib,pbRle,dx);
  201.             pbDib += wWidthBytes;
  202.     }
  203.  
  204.     GEN_EOF(pbRle);
  205.  
  206.         lpbi->biSizeImage = (long)(pbRle-pbRleT);
  207.         lpbi->biCompression = BI_RLE8;
  208.     return (long)(pbRle-pbRleT);
  209.     }
  210.  
  211.     //
  212.     //  start the delta framin'
  213.     //
  214.     x = 0;
  215.     y = 0;
  216.  
  217.     while (y<dy)
  218.     {
  219. #ifdef DEBUG
  220.         if (pbDib != pbDibT + x + (DWORD)y*wWidthBytes)
  221.         DebugBreak();
  222.         if ((DWORD)pbRle & 1)
  223.         DebugBreak();
  224. #endif
  225.     jx = FindJumpLength(pbDib, dx-x, uColor);
  226.  
  227.     if (x+jx == dx)   // we have a multi-line jump
  228.         {
  229.             pbDib  += jx + wNextScan;
  230.  
  231.         for (jy=1; y+jy<dy && (jx=FindJumpLength(pbDib, dx, uColor))==dx; jy++)
  232.             {
  233.                 pbDib  += wWidthBytes;
  234.             }
  235.  
  236.             if (jy+y >= dy)
  237.                 goto done;
  238.  
  239.             if (jx < x)
  240.             {
  241.                 GEN_EOL(pbRle);
  242.                 jy--;
  243.                 y++;
  244.                 x=0;
  245.             }
  246.  
  247.             GEN_JUMP(pbRle, jx-x, jy);
  248.  
  249.             x  = 0;
  250.             y += jy;
  251.         }
  252.     else if (jx > 0)
  253.         {
  254.             //
  255.         //    we have a "normal" jump
  256.             //
  257.             GEN_JUMP(pbRle,jx,0);
  258.     }
  259.     else if (jx = FindFragmentLength(pbDib, dx-x, uColor))
  260.     {
  261.             pbRle = EncodeFragment(pbDib, pbRle, jx);
  262.     }
  263.  
  264.         x      += jx;
  265.         pbDib  += jx;
  266.     }
  267.  
  268.     //
  269.     // all done.
  270.     //
  271. done:
  272.     GEN_EOF(pbRle);
  273.  
  274.     lpbi->biSizeImage = (long)(pbRle-pbRleT);
  275.     lpbi->biCompression = BI_RLE8;
  276.     return (long)(pbRle-pbRleT);
  277. }
  278.  
  279. //
  280. //  MakeRleDib
  281. //
  282. //
  283. LPBITMAPINFOHEADER MakeRleDib(
  284.     LPBITMAPINFOHEADER lpbi,    // packed DIB
  285.     UINT               uColor)  // trasnparent color (-1 for upper corner)
  286. {
  287.     LPBITMAPINFOHEADER p;
  288.  
  289.     p = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, DibSize(lpbi) * 2);
  290.     hmemcpy(p, lpbi, lpbi->biSize + DibPaletteSize(lpbi));
  291.  
  292.     if (uColor == (UINT)-1)
  293.         uColor = ((LPBYTE)DibXY(lpbi,0,0))[0];
  294.  
  295.     RleDib(p, DibPtr(lpbi), uColor, DibPtr(p));
  296.  
  297.     GlobalReAllocPtr(p, DibSize(p), 0);
  298.  
  299.     return p;
  300. }
  301.